package com.cloud.service.sys;

import com.cloud.app.AppConstant;
import com.cloud.enums.BaseRole;
import com.cloud.enums.DataLevel;
import com.cloud.app.utils.AuthorityUtil;
import com.cloud.app.utils.SessionUtil;
import com.cloud.model.*;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.jpa.repository.JpaRepository;

import com.cloud.core.exception.WorldValidateException;
import com.cloud.dao.RoleDao;
import com.cloud.dao.RoleMenuDao;
import com.cloud.dao.RoleResourceDao;
import com.cloud.pojo.Result;
import com.cloud.pojo.WorldPage;
import com.cloud.util.CollectionUtil;
import com.cloud.util.SysUtil;
import org.apache.log4j.Logger;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.cloud.enums.DataLevel.ALL;

@Service
@Transactional
public class RoleService extends BaseService<Role> {
    private static final Logger logger = Logger.getLogger(RoleService.class);
    public static Map<String, Role> roleIdRoleMap = new ConcurrentHashMap<>();

    @Override
    public JpaRepository getDao() {
        return roleDao;
    }

    @Resource
    private RoleDao roleDao;
    @Resource
    private RoleResourceDao roleResourceDao;
    @Resource
    private RoleMenuDao roleMenuDao;
    @Resource
    private UserService userService;
    @Resource
    JPAQueryFactory jpaQueryFactory;

    public Page<Role> page(Role entity, WorldPage worldPage) throws Exception {
        User user = SessionUtil.getUser();

        QRole qRole = QRole.role;
        JPAQuery<Role> query = jpaQueryFactory.selectFrom(qRole);
        if (!AuthorityUtil.hasRole(BaseRole.ROLE_ROOT)) {
            query = query.where(qRole.roleKey.ne(BaseRole.ROLE_ROOT.name()));
            //首先要计算登陆用户的最高角色的level
            DataLevel userDataLevel = userService.getDataLevel(user);
            List<DataLevel> dataLevels = DataLevel.getLteDataLevels(userDataLevel);
            query.where(qRole.dataLevel.in(dataLevels));
            query.where(qRole.roleKey.ne(user.getRole().getRoleKey()));
        }
        switch (userService.getDataLevel(user)) {
            case ALL:
                break;
            default:
                query = query.where(qRole.id.eq("-1"));
                break;
        }
        query.orderBy(qRole.createTime.asc());
        long total = query.fetchCount();
        List<Role> list = query.offset(worldPage.getPageIndex() * worldPage.getPageSize()).limit(worldPage.getPageSize()).fetch();
        Page<Role> page = new PageImpl<>(list, worldPage.getPageRequest(), total);

        return page;
    }

    public List<Role> getCanSelect() {
        User user = SessionUtil.getUser();
        QRole qRole = QRole.role;
        JPAQuery<Role> query = jpaQueryFactory.selectFrom(qRole);
        if (!AuthorityUtil.hasRole(BaseRole.ROLE_ROOT)) {
            query.where(qRole.roleKey.ne(BaseRole.ROLE_ROOT.name()));
            DataLevel userDataLevel = userService.getDataLevel(user);
            List<DataLevel> dataLevels = DataLevel.getLteDataLevels(userDataLevel);
            query.where(qRole.dataLevel.in(dataLevels));
        }
        query.where(qRole.id.ne(user.getRole().getId()));
        List<Role> roles = query.fetch();
        return roles;
    }

    public void del(String[] ids) {
        Set<String> roleIds = CollectionUtil.arrayToSet(ids);
        QRole qRole = QRole.role;
        JPAQuery<Role> query = jpaQueryFactory.selectFrom(qRole);
        List<Role> roles = query.where(qRole.id.in(ids)).fetch();
        if (CollectionUtil.isNotEmpty(roles)) {
            for (Role role : roles) {
                for (BaseRole baseRole : BaseRole.values()) {
                    if (baseRole.name().equals(role.getRoleKey())) {
                        throw new WorldValidateException("基础角色不能删除");
                    }
                }
            }
            roleDao.deleteInBatch(roles);
            for (Role role : roles) {
                roleIdRoleMap.remove(role.getId());
            }
        }
        //删除角色的时候要清理roleResource表和userRole表还有roleMenu
        QRoleResource qRoleResource = QRoleResource.roleResource;
        JPAQuery<RoleResource> roleResourceJPAQuery = jpaQueryFactory.selectFrom(qRoleResource);
        List<RoleResource> roleResources = roleResourceJPAQuery.where(qRoleResource.roleId.in(roleIds)).fetch();
        roleResourceDao.deleteAll(roleResources);

        QRoleMenu qRoleMenu = QRoleMenu.roleMenu;
        JPAQuery<RoleMenu> roleMenuJPAQuery = jpaQueryFactory.selectFrom(qRoleMenu);
        List<RoleMenu> roleMenus = roleMenuJPAQuery.where(qRoleResource.roleId.in(roleIds)).fetch();
        roleMenuDao.deleteAll(roleMenus);
    }

    public Result saveRole(Role role) {
        if (SysUtil.isEmpty(role.getRoleName())) {
            return new Result(false, "角色名称不能为空!");
        }
        if (role.getDataLevel() == null) {
            return new Result(false, "数据权限不能为空!");
        }
        Role roleExist = null;
        if (SysUtil.isEmpty(role.getId())) {//添加
            roleExist = roleDao.findByRoleName(role.getRoleName());
            if (roleExist != null) {
                return new Result(false, "角色已经存在");
            }
            roleExist = new Role();
            roleExist.setRoleKey("ROLE_" + role.getRoleName());
            roleExist.setRoleName(role.getRoleName());
            roleExist.setDataLevel(role.getDataLevel());
            roleExist = roleDao.save(roleExist);
        } else {//编辑
            roleExist = roleDao.getOne(role.getId());
            if (roleExist != null) {
                boolean ifBaseRole = false;
                for (BaseRole baseRole : BaseRole.values()) {
                    if (baseRole.name().equals(roleExist.getRoleKey())) {
                        ifBaseRole = true;
                    }
                }
                if (!ifBaseRole) {
                    //基础角色不更改key
                    roleExist.setRoleKey("ROLE_" + role.getRoleName());
                }
                roleExist.setRoleName(role.getRoleName());
                roleExist.setDataLevel(role.getDataLevel());
                roleExist = roleDao.save(roleExist);
            } else {
                return new Result(false, "角色不存在");
            }
        }

        roleIdRoleMap.put(roleExist.getId(), roleExist);
        return new Result(true, "成功", roleExist);
    }

    public Role getRole(String id) {
        return roleDao.findById(id).get();
    }

    public void initBaseRole() {
        for (BaseRole baseRole : BaseRole.values()) {
            Role role = roleDao.findByRoleKey(baseRole.name());
            if (role == null) {
                role = new Role(baseRole.name(), baseRole.getName());
                Role o = roleDao.save(role);
                RoleService.roleIdRoleMap.put(o.getId(), o);
            }
        }
    }

    public void initRoleCache() {
        List<Role> os = roleDao.findAll();
        if (CollectionUtil.isNotEmpty(os)) {
            for (Role o : os) {
                RoleService.roleIdRoleMap.put(o.getId(), o);
            }
        }
    }

    //新建角色的时候可选择的可控数据范围，要根据用户的角色的最高的datalevel来确定
    public List<DataLevel> getCanSelDataLevels(String username) {
        User user = userService.getByUsername(username);
        DataLevel topDataLevel = userService.getDataLevel(user);
        List<DataLevel> dataLevels = new ArrayList<>();
        for (DataLevel dataLevel : DataLevel.values()) {
            if (dataLevel.getLevel() >= topDataLevel.getLevel()) {
                dataLevels.add(dataLevel);
            }
        }

        return dataLevels;
    }
}
